package com.young.springboot.basic.service.mail.impl;


import com.young.springboot.basic.event.AsyncMailEvent;
import com.young.springboot.basic.service.mail.MailService;
import com.young.springboot.basic.vo.mail.MailVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.EventListener;
import org.springframework.core.io.*;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author hyy
 */
@EnableAsync
@Service
public class MailServiceImpl  implements MailService {

    private static final Logger logger = LoggerFactory.getLogger("views/mail");

    /**
     * Spring Boot 提供了一个发送邮件的简单抽象，使用的是下面这个接口，这里直接注入即可使用
     */
    @Autowired
    private JavaMailSenderImpl mailSender;

    /**
     * spring 异步事件发布者
     */
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;


    /**
     * 简单文本邮件
     * @param vo
     */
    @Override
    public void sendSimpleMail(MailVo vo) {
        checkMail(vo);
        //创建SimpleMailMessage对象
        SimpleMailMessage message = new SimpleMailMessage();
        //邮件发送人
        message.setFrom(getMailSendFrom());
        //邮件接收人
        message.setTo(vo.getTo());
        //邮件主题
        message.setSubject(vo.getSubject());
        //邮件内容
        message.setText(vo.getText());
        //发送邮件
        mailSender.send(message);
    }

    /**
     * html邮件
     *
     */
    @Override
    public void sendHtmlMail(MailVo vo) {
        checkMail(vo);
        //获取MimeMessage对象
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper messageHelper;
        try {
            messageHelper = new MimeMessageHelper(message, true);
            //邮件发送人
            messageHelper.setFrom(getMailSendFrom());
            //邮件接收人
            messageHelper.setTo(vo.getTo());
            //邮件主题
            message.setSubject(vo.getSubject());
            //邮件内容，html格式
            messageHelper.setText(vo.getText(), true);
            //发送
            mailSender.send(message);
            //日志信息
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 带附件的邮件
     *
     */
    @Override
    public void sendAttachmentsMail(MailVo vo) {
        checkMail(vo);
        MimeMessage message = mailSender.createMimeMessage();
        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(getMailSendFrom());
            helper.setTo(vo.getTo());
            helper.setSubject(vo.getSubject());
            helper.setText(vo.getText(), true);

            String filePath = vo.getFilePath();
            FileSystemResource file = new FileSystemResource(new File(filePath));
            String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
            helper.addAttachment(fileName, file);
            mailSender.send(message);
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }


    /**
     * 接收前端数据，发送邮件
     */
    @Override
    public MailVo sendMail(MailVo mailVo) {
        try {
            checkMail(mailVo);
            AsyncMailEvent asyncMailEvent = new AsyncMailEvent(this.getClass().getName());
            asyncMailEvent.setMailVo(mailVo);
            applicationEventPublisher.publishEvent(asyncMailEvent);
            //sendMimeMail(mailVo);
            return saveMail(mailVo);
        } catch (Exception e) {
            logger.error("发送邮件失败:", e);
            mailVo.setStatus("fail");
            mailVo.setError(e.getMessage());
            return mailVo;
        }

    }

    /**
     * 检查发送邮件锁必须的属性是否为空
     * @param mailVo
     */
    private void checkMail(MailVo mailVo) {
        if (StringUtils.isEmpty(mailVo.getTo())) {
            throw new RuntimeException("邮件收信人不能为空");
        }
        if (StringUtils.isEmpty(mailVo.getSubject())) {
            throw new RuntimeException("邮件主题不能为空");
        }
        if (StringUtils.isEmpty(mailVo.getText())) {
            throw new RuntimeException("邮件内容不能为空");
        }
    }

    /**
     * 使用异步监听的方式发送邮件
     * @param asyncMailEvent
     */
    @Async
    @EventListener
    public void asyncSendMineMail(AsyncMailEvent asyncMailEvent){
        Object source = asyncMailEvent.getSource();
        logger.info("异步事件发起源：{}",source.toString());
        MailVo mailVo = asyncMailEvent.getMailVo();
        sendMimeMail(mailVo);
    }

    /**
     * Mime:多用途互联网邮件扩展
     * @param mailVo
     */
    private void sendMimeMail(MailVo mailVo) {
        try {
            //true表示支持复杂类型
            MimeMessageHelper messageHelper = new MimeMessageHelper(mailSender.createMimeMessage(), true);
            //邮件发信人从配置项读取
            mailVo.setFrom(getMailSendFrom());
            //邮件发信人
            messageHelper.setFrom(mailVo.getFrom());
            //邮件收信人
            messageHelper.setTo(mailVo.getTo().split(","));
            //邮件主题
            messageHelper.setSubject(mailVo.getSubject());
            //邮件内容
            messageHelper.setText(mailVo.getText());
            //抄送
            if (!StringUtils.isEmpty(mailVo.getCc())) {
                messageHelper.setCc(mailVo.getCc().split(","));
            }
            //密送
            if (!StringUtils.isEmpty(mailVo.getBcc())) {
                messageHelper.setCc(mailVo.getBcc().split(","));
            }
            //添加邮件附件
            MultipartFile[] multipartFiles = mailVo.getMultipartFiles();
            if (multipartFiles != null) {
                /*此种方式适合异步发送邮件，若不将附件以流的形式保存，则由于springboot主线程结束后会清理临时文件，所以会出现文件找不到的异常*/
                byte[][] attachFileBytes = mailVo.getAttachFileBytes();
                for (int i = 0; i < multipartFiles.length; i++) {
                    MultipartFile multipartFile = multipartFiles[i];
                  new InputStreamResource(multipartFile.getInputStream());
                    messageHelper.addAttachment(multipartFile.getOriginalFilename(),
                            new ByteArrayResource(attachFileBytes[i]));
                }

                /**
                 * 以下情况适合非异步发送邮件
                 */
                /*for (MultipartFile multipartFile : multipartFiles) {
                    messageHelper.addAttachment(multipartFile.getOriginalFilename(), multipartFile);
                }*/
            }
            //发送时间
            if (StringUtils.isEmpty(mailVo.getSentDate())) {
                mailVo.setSentDate(new Date());
                messageHelper.setSentDate(mailVo.getSentDate());
            }
            //正式发送邮件
            mailSender.send(messageHelper.getMimeMessage());
            mailVo.setStatus("ok");
            logger.info("发送邮件成功：{}->{}", mailVo.getFrom(), mailVo.getTo());
        } catch (Exception e) {
            //发送失败
            throw new RuntimeException(e);
        }
    }

    /**
     * 将邮件进行保存
     * @param mailVo
     * @return
     */
    private MailVo saveMail(MailVo mailVo) {
        //将邮件保存到数据库..
        return mailVo;
    }

    /**
     * 获取邮件发送人
     * @return
     */
    @Override
    public String getMailSendFrom() {
        return mailSender.getJavaMailProperties().getProperty("from");
    }







    private String getHtmlEmail(String code, String company,Integer timeout) {
        String htmlEmail = "<!DOCTYPE html>\n" +
                "<html>\n" +
                "<head>\n" +
                "<title></title>\n" +
                "<style>\n" +
                ".qmbox {\n" +
                "\tpadding: 0;\n" +
                "}\n" +
                ".qm_con_body_content {\n" +
                "\theight: auto;\n" +
                "\tmin-height: 100px;\n" +
                "\t_height: 100px;\n" +
                "\tword-wrap: break-word;\n" +
                "\tfont-size: 14px;\n" +
                "\tfont-family: \"lucida Grande\", Verdana, \"Microsoft YaHei\";\n" +
                "}\n" +
                ".body {\n" +
                "\tline-height: 170%;\n" +
                "}\n" +
                "BODY {\n" +
                "\tfont-family: \"lucida Grande\", Verdana, \"Microsoft YaHei\";\n" +
                "\tfont-size: 12px;\n" +
                "\t-webkit-font-smoothing: subpixel-antialiased;\n" +
                "}\n" +
                "BODY {\n" +
                "\tmargin: 0;\n" +
                "\tpadding: 0;\n" +
                "}\n" +
                "BODY {\n" +
                "\tbackground-color: #fff;\n" +
                "\tfont-size: 12px;\n" +
                "}\n" +
                "BODY {\n" +
                "\tbackground: #fff;\n" +
                "}\n" +
                "BODY {\n" +
                "\tbackground: #fff;\n" +
                "\tcolor: #000;\n" +
                "\tfont-weight: normal;\n" +
                "\tfont-family: \"lucida Grande\", Verdana, \"Microsoft YaHei\";\n" +
                "\tpadding: 0 7px 6px 4px;\n" +
                "\tmargin: 0;\n" +
                "}\n" +
                "HTML {\n" +
                "\ttop: 0px;\n" +
                "}\n" +
                ".body P {\n" +
                "\tline-height: 170%;\n" +
                "}\n" +
                "</style>\n" +
                "</head>\n" +
                "\n" +
                "<BODY mu=\"mu\" md=\"md\" module=\"qmReadMail\" context=\"ZC1912-rQ7uXSy7P7HThxdLFCOuY92\"><DIV class=mailcontainer id=qqmail_mailcontainer>\n" +
                "<DIV id=mainmail style=\"MARGIN-BOTTOM: 12px; POSITION: relative; Z-INDEX: 1\">\n" +
                "<DIV class=body id=contentDiv style=\"FONT-SIZE: 14px; HEIGHT: auto; POSITION: relative; ZOOM: 1; PADDING-BOTTOM: 10px; PADDING-TOP: 15px; PADDING-LEFT: 15px; Z-INDEX: 1; LINE-HEIGHT: 1.7; PADDING-RIGHT: 15px\" onmouseover=getTop().stopPropagation(event); onclick=\"getTop().preSwapLink(event, 'html', 'ZC1912-rQ7uXSy7P7HThxdLFCOuY92');\">\n" +
                "<DIV id=qm_con_body>\n" +
                "<DIV class=\"qmbox qm_con_body_content qqmail_webmail_only\" id=mailContentContainer>\n" +
                "<DIV class=main style=\"OVERFLOW: hidden; WIDTH: 100%; BACKGROUND-COLOR: #f7f7f7\">\n" +
                "<DIV class=content style=\"BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; BACKGROUND: #ffffff; BORDER-BOTTOM: #cccccc 1px solid; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 25px; BORDER-LEFT: #cccccc 1px solid; MARGIN: 50px; PADDING-RIGHT: 25px\">\n" +
                "<DIV class=header style=\"MARGIN-BOTTOM: 30px\">\n" +
                "<P>亲爱的用户：</P></DIV>\n" +
                "<P>您好！您正在进行邮箱验证，本次请求的验证码为：</P>\n" +
                "<P><SPAN style=\"FONT-SIZE: 18px; FONT-WEIGHT: bold; COLOR: #f90\">" + code + "</SPAN><SPAN style=\"COLOR: #000000\">(为了保障您帐号的安全性，请在"+timeout+"分钟内完成验证)</SPAN></P>\n" +
                "<DIV class=footer style=\"MARGIN-TOP: 30px\">\n" +
                "<P>" + company + "</P>\n" +
                "<P><SPAN style=\"BORDER-BOTTOM: #ccc 1px dashed; POSITION: relative; _display: inline-block\" t=\"5\" times=\"\" isout=\"0\">2019-02-12</SPAN></P></DIV>\n" +
                "<DIV class=tip style=\"COLOR: #cccccc; TEXT-ALIGN: center\">该邮件为系统自动发送，请勿进行回复 </DIV></DIV></DIV></DIV></DIV></DIV></DIV></DIV></BODY>\n" +
                "</html>\n";
        return htmlEmail;
    }






    /**
     * 邮件内容头部
     *
     * @param websiteName    网站名称
     * @param principal      网站主页
     * @param principalImage 网站logo图片超链接
     * @param logoWidth      logo图片宽度
     * @param logoHeight     logo图片高度
     * @return
     */
    private static String mailHead(String websiteName, String principal, String principalImage, String logoWidth, String logoHeight) {
        return "<div style=\"margin: 0 auto; text-align: left;\n" +
                "padding: 38px 50px; width: 560px; font-size: 14px;\n" +
                "color: #606060; background: #fff; border-radius:\n" +
                "2px; font-family:Tahoma,Helvetica,'microsoft\n" +
                "yahei','Hiragino Sans GB',Simsun,sans-serif;\n" +
                "box-shadow: 0 0 4px rgba(0,0,0,0.2);\">\n" +
                "        <table style=\"margin: 0 auto;\n" +
                "text-align: left; font-size: 14px; color: #606060;\n" +
                "background: #fff; font-family: inherit;\n" +
                "font-family:Tahoma,Helvetica,'microsoft\n" +
                "yahei','Hiragino Sans GB',Simsun,sans-serif;\" width=\"560\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\">\n" +
                "            <tbody><tr>\n" +
                "                <th colspan=\"2\"><a href=\"" + principal + "\" rel=\"noopener\" target=\"_blank\"><img src=\"" + principalImage + "\" width=\"" + logoWidth + "\" height=\"" + logoHeight + "\"></a></th>\n" +
                "            </tr>\n" +
                "            <tr>\n" +
                "                <td colspan=\"2\" style=\"font-size:\n" +
                "18px; padding: 30px 0\n" +
                "18px;\">尊敬的" + websiteName + "用户：</td>\n" +
                "            </tr>\n" +
                "            <tr>\n" +
                "                <td colspan=\"2\" style=\"line-height: 1.8;\">\n" +
                "                   \n" +
                "<div>欢迎使用" + websiteName + "！</div>\n";
    }

    /**
     * 邮件内容脚部
     *
     * @param websiteName 网站名称
     * @param principal   网站主页
     * @param qrCode      二维码图片链接(可不填写/仅支持第一张)
     * @return
     */
    private static String mailFoot(String websiteName, String principal, String... qrCode) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
        String nowDate = sdf.format(new Date());
        return "            <tr>\n" +
                "                <td colspan=\"2\" style=\"text-align:\n" +
                "right; line-height: 1.8; padding-bottom: 18px;\">\n" +
                "                    <div>" + websiteName + "团队</div>\n" +
                "                    <div style=\"color:\n" +
                "#909090;\">" + nowDate + "</div>\n" +
                "                </td>\n" +
                "            </tr>\n" +
                (qrCode != null && qrCode.length != 0 ? setQrCode(websiteName, qrCode[0]) : "") +
                "            <tr>\n" +
                "                <td colspan=\"2\" style=\"padding-top: 20px; border-top: 1px solid\n" +
                "#e7e7e7; line-height: 1.8; font-size: 12px; color:\n" +
                "#909090;\">\n" +
                "                    <div>温馨提示：</div>\n" +
                "                    <div>1.\n" + websiteName +
                "官方网址为：<a href=\"" + principal + "\" rel=\"noopener\" target=\"_blank\">" + principal + "</a>，请注意网址，防止钓鱼。</div>\n" +
                "                    <div>2.\n" +
                "本邮件为系统自动发出，请勿回复。</div>\n" +
                "                </td>\n" +
                "            </tr>\n" +
                "        </tbody></table>\n" +
                "    </div>";
    }

    /**
     * 输出漂亮格式(带logo,可带二维码)
     *
     * @param websiteName    网站名称
     * @param principal      主页地址
     * @param principalImage 主页logo 323 x 48 拉伸宽度为 (超链接形式)
     * @param business       业务
     * @param qrCode         二维码 (超链接形式)
     * @return
     */
    private static String prettyLayout(String websiteName, String principal, String principalImage, String business, String... qrCode) {
        return mailHead(websiteName, principal, principalImage, "", "") +
                business +
                mailFoot(websiteName, principal, qrCode);


    }


    /**
     * 二维码 样式A
     *
     * @param websiteName //网站名称
     * @param qrCode      //二维码图片链接
     * @return
     */
    private static String setQrCode(String websiteName, String qrCode) {
        return "            <tr>\n" +
                "                <td style=\"padding-bottom: 20px;\" width=\"145\">\n" +
                "                    <img src=\"" + qrCode + "\" width=\"110\" height=\"112\">\n" +
                "                </td>\n" +
                "                <td style=\"line-height: 2;\n" +
                "padding-bottom: 20px;\">\n" +
                "                    <div style=\"font-size: 18px;\n" +
                "color:\n" +
                "#03c5ff;\">扫描关注" + websiteName + "公众号</div>\n" +
                "                </td>\n" +
                "            </tr>\n";
    }

    /**
     * 发送邮箱验证码
     *
     * @param validity   有效期/单位自行填写
     * @param verifyCode 验证码
     * @return
     */
    private static String prettyQrCodeLayout(String validity, String verifyCode) {
        return "<div>邮箱验证码的有效期为:" + validity + "邮箱验证码如下:</div>\n" +
                "                </td>\n" +
                "            </tr>\n" +
                "            <tr>\n" +
                "                <td colspan=\"2\" style=\"font-size:\n" +
                "12px; line-height: 20px; padding-top: 14px;\n" +
                "padding-bottom: 25px; color: #909090;\">\n" +
                "                    <div>" + verifyCode + "</div>\n" +
                "                </td>\n" +
                "            </tr>\n";
    }

    /**
     * 发送邮箱注册激活链接
     *
     * @param validity    有效期/单位自行填写
     * @param websiteName 网站名
     * @param verifyLink  注册验证链接
     * @return
     */
    private static String prettyRegisterLayout(String validity, String websiteName, String verifyLink) {
        return "<div>请点击以下的链接验证您的邮箱，验证成功后就可以使用" + websiteName + "提供的服务了。</div>\n" +
                "                </td>\n" +
                "            </tr>\n" +
                "            <tr>\n" +
                "                <td colspan=\"2\" style=\"font-size:\n" +
                "12px; line-height: 20px; padding-top: 14px;\n" +
                "padding-bottom: 25px; color: #909090;\">\n" +
                "                    <div>该链接的有效期为" + validity + "，如链接超过有效期请重新发送邮件<a href=\"" + verifyLink + "\" style=\"color: #03c5ff; text-decoration:\n" +
                "underline;\" rel=\"noopener\" target=\"_blank\">" + verifyLink + "</a></div>\n" +
                "                    <div style=\"padding-top:\n" +
                "4px;\">(如果不能打开页面，请复制该地址到浏览器打开)</div>\n" +
                "                </td>\n" +
                "            </tr>\n";
    }


}
